package com.yonyou.iuap.pub;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import org.apache.log4j.Logger;
import org.csource.common.MyException;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.ClientGlobal;
import org.csource.fastdfs.FileInfo;
import org.csource.fastdfs.ServerInfo;
import org.csource.fastdfs.StorageClient;
import org.csource.fastdfs.StorageServer;
import org.csource.fastdfs.TrackerClient;
import org.csource.fastdfs.TrackerServer;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.StringUtils;

import com.yonyou.iuap.base.vo.FastDfsMsgVO;
import com.yonyou.iuap.shell.util.ShellUtils;


/**
 * File Manager used to provide the services to upload / download / delete the files
 * from FastDFS.
 * 
 * <note>In this version, FileManager only support single tracker, will enhance this later...</note>
 * 
 * @author zlj
 *
 */
public class FileManager implements FileManagerConfig {

	private static final long serialVersionUID = 1L;

	private static Logger logger  = Logger.getLogger(FileManager.class);

	private static TrackerClient  trackerClient;
	private static TrackerServer  trackerServer;
	private static StorageServer  storageServer;
	private static StorageClient  storageClient;

	static { // Initialize Fast DFS Client configurations

		try {
			ClassPathResource cpr = new ClassPathResource(CLIENT_CONFIG_FILE);
			String configFileName =cpr.getClassLoader().getResource(CLIENT_CONFIG_FILE).getPath();
			ClientGlobal.init(configFileName);

			trackerClient = new TrackerClient();
			trackerServer = trackerClient.getConnection();

			storageClient = new StorageClient(trackerServer, storageServer);

		} catch (Exception e) {
			logger.error(logger,  e);
		}
	}



	public static FastDfsMsgVO upload(FastDFSFile file) throws IOException {
		String[] uploadResults = null;
		FastDfsMsgVO msgvo = new FastDfsMsgVO();
		int status = 0 ;
		String msg = "上传完成！";
		if((file==null || file.getFile()==null) && (file.getBytes()==null || file.getBytes().length==0)){
			msg="没有需要上传的文件!";
			status = -1;
			msgvo.setStatus(status);
			msgvo.setMsg(msg);
			return msgvo;
		}
		NameValuePair[] meta_list = new NameValuePair[5];
		meta_list[0] = new NameValuePair("width", file.getWidth());
		meta_list[1] = new NameValuePair("heigth", file.getHeight());
		meta_list[2] = new NameValuePair("author", file.getAuthor());
		meta_list[3] = new NameValuePair("fileName", file.getName());
		meta_list[4] = new NameValuePair("fileExtName", file.getExt());

		long startTime = System.currentTimeMillis();
		byte[] file_content = null;
		try {
			if(file.getBytes()!=null && file.getBytes().length>0){
				file_content = file.getBytes();
			}else if(file.getFile()!=null){
				file_content = getFileBuffer(new FileInputStream(file.getFile()), file.getFile().length());
			}else if(file.getInput()!=null){
				file_content = getFileBuffer(file.getInput(), file.getFile().length());
			}
			if(file_content==null){
				logger.error("未获取到文件内容");
				msg ="未获取到文件内容";
				status = -1;
			}else{
				uploadResults = storageClient.upload_file(file_content, file.getExt(), meta_list);
			}
			msgvo.setFile_size(ShellUtils.getFileSize(file_content.length));
		} catch (IOException e) {
			logger.error("IO Exception when uploadind the file: " + file.getName(), e);
			msg="【IOException：】"+e.getMessage();
			status = -1 ;
		} catch (Exception e) {
			logger.error("Non IO Exception when uploadind the file: " + file.getName(), e);
			msg="【Exception：】"+e.getMessage();
			status = -1;
		}finally{
			if(trackerServer!=null){
				trackerServer.close();
			}
		}
		logger.info("upload_file time used: " + (System.currentTimeMillis() - startTime) + " ms");

		if (uploadResults == null) {
			logger.error( "upload file fail, error code: " + storageClient.getErrorCode());
		}

		String groupName 		= uploadResults[0];
		String remoteFileName   = uploadResults[1];

		String fileAbsolutePath = PROTOCOL + trackerServer.getInetSocketAddress().getHostName() 
				+ ":"
				+ TRACKER_NGNIX_PORT
				+ SEPARATOR 
				+ groupName 
				+ SEPARATOR 
				+ remoteFileName;
				


		logger.info( "upload file successfully!!!  " +"group_name: " + groupName + ", remoteFileName:"
				+ " " + remoteFileName);
		
		msgvo.setFile_url(fileAbsolutePath);
		msgvo.setUploadResult(uploadResults);
		msgvo.setMsg(msg);
		msgvo.setStatus(status);
		
		return msgvo;

	}

	public static FileInfo getFile(String groupName, String remoteFileName) {
		try {
			return storageClient.get_file_info(groupName, remoteFileName);
		} catch (IOException e) {
			logger.error("IO Exception: Get File from Fast DFS failed", e);
		} catch (Exception e) {
			logger.error("Non IO Exception: Get File from Fast DFS failed", e);
		}
		return null;
	}
	public static byte[] downFile(String groupName, String remoteFileName)throws Exception{
		try {
			return storageClient.download_file(groupName, remoteFileName);
		} catch (IOException e) {
			logger.error("IO Exception: download_file from Fast DFS failed", e);
		} catch (MyException e) {
			logger.error("MyException: download_file from Fast DFS failed", e);
		}
		return null;
	}
	public static int  deleteFile(String groupName, String remoteFileName) throws Exception {
		int i_rs = storageClient.delete_file(groupName, remoteFileName);
		return i_rs;
	}

	public static StorageServer[] getStoreStorages(String groupName) throws IOException {
		return trackerClient.getStoreStorages(trackerServer, groupName);
	}

	public static ServerInfo[] getFetchStorages(String groupName, String remoteFileName) throws IOException {
		return trackerClient.getFetchStorages(trackerServer, groupName, remoteFileName);
	}
	private static byte[] getFileBuffer(InputStream inStream, long fileLength) throws IOException {

        byte[] buffer = new byte[256 * 1024];
        byte[] fileBuffer = new byte[(int) fileLength];

        int count = 0;
        int length = 0;

        while ((length = inStream.read(buffer)) != -1) {
            for (int i = 0; i < length; ++i) {
                fileBuffer[count + i] = buffer[i];
            }
            count += length;
        }
        return fileBuffer;
    }
}